<?php

namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\WebDriverSelect;

require_once('vendor/autoload.php');


class Auto
{
    public $robot_id = 1;
    public $captcha_try_num = 20;
    public $find_captcha_try_num = 6;
    public $email_try_num = 7;
    public $log_arr = [];
    public $host = 'http://localhost:9515';
    protected $user = [];
    public $email_link = '';
    public $email_api = 'http://auto.asovip.com//email/mailfromlist';
    public $email_sync_status_api = 'http://auto.asovip.com/email/regresult';
    public $appid_pass ='';
    public $email = [];
    protected $driver = null;
    public $curl_verbose = 0;
    public $debug = 1;
    public $create_page_wait = 10;
    public $create_page_submit_wait = 5;

    const SECRUE_TOKEN_KEY = 'testin.cn';
    const SYSTEM_SUCCESS = 0;
    const SYSTEM_FAILED = 1;
    const POP3_SUCCESS = 0;
    const POP3_FAILED = 1;
    const HOST = 'pop3.sohu.com';
    const PORT = '110';
    const MAIL_TIMAE_OUT = 10; //ms  代理连接超时和获取邮件正文超时的时间设定
    /**
     * 主控制开始
     */
    public function start()
    {
        //获取邮箱,
        $email = $this->getNewEmail();
        if (empty($email)) {
            die;
        }
        $this->email = $email;
        $this->logSave(['email' => var_export($email,true)]);

        //收邮件
        $email_link = $this->getmaillink($this->email['email'], $this->email['email_pass']);

        $this->logSave(['email_link' => var_export($email_link,true)]);

        if (empty($email_link) || !is_array($email_link) || $email_link['errno'] != self::SYSTEM_SUCCESS || $email_link['data']['status'] != self::POP3_SUCCESS) {
            die;
        }
        $this->email_link = $email_link['data']['reason'];
        $this->appid_pass = $this->email['apple_pass'];
        $this->appid_pass = 1234;
//        $this->log_arr['robot_id'] = $this->robot_id;
        $this->logSave(['tips' => 'Start...']);
        $this->initChrome();
        sleep(1);
        $init_page_ret = $this->initPage();
        if (!$init_page_ret) {
            $this->logSave(['tips' => 'Create Page Loading Failed']);
            $this->quit();
        }
        $this->inputPass();
        sleep(1);
        $this->createSubmit();
        sleep(1);
        $check_ok = $this->checkStatus();
        if (!$check_ok) {
            $this->logSave(['tips' => 'pass error']);
            $this->syncStatus(2);
            $this->logSave(['tips' => 'End...']);
            $this->quit();
        } else {
            $this->logSave(['tips' => 'pass success']);
            $this->syncStatus(1);
        }
        sleep(1);
        $this->logSave(['tips' => 'End...']);
        $this->quit();
    }

    protected function getNewEmail()
    {
        //return 'tuolemeiguai@sohu.com';
        $timestamp = time();
        $token = $this->getToken($timestamp);
        $api = $this->email_api . '?robot_id=' . $this->robot_id . '&token=' . $token . '&timestamp=' . $timestamp;

        $ret = $this->httpGet($api);

        if ($ret['errno'] != 0) {
            $this->logSave(['tips' => 'Get New Email Error:' . $ret['error']]);
            return false;
        }

        $data = json_decode($ret['data'], true);
        if ($data['errno'] == 0) {
            return $data['data'];
        }
        return false;
    }

    public function getToken($timestamp){
        $token = sha1(self::SECRUE_TOKEN_KEY . $timestamp . $this->robot_id);
        return $token ? $token : '';
    }


    protected function initChrome()
    {
        $capabilities = [
            WebDriverCapabilityType::BROWSER_NAME => 'chrome',
        ];

        $proxy_info = $this->getProxy();
        if ($proxy_info) {
            $capabilities[WebDriverCapabilityType::PROXY] = [
                'proxyType' => 'manual',
                'httpProxy' => $proxy_info['host'] . ':' . $proxy_info['port'],
                'httpsProxy' => $proxy_info['host'] . ':' . $proxy_info['port'],
            ];
        }

        $this->driver = RemoteWebDriver::create($this->host, $capabilities, 5000);

        $this->driver->get($this->email_link);
    }

    protected function getProxy()
    {
//        return [
//            'host' => '140.224.76.42',
//            'port' => '808',
//        ];

        return [
            'host' => '42.51.206.156',
            'port' => '16816',
        ];
    }

    protected function initPage()
    {
        try {
            $this->driver->wait($this->create_page_wait, 500)->until(
                WebDriverExpectedCondition::visibilityOfElementLocated(
                    WebDriverBy::className('myappleid')
                )
            );
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    protected function findCaptcha()
    {
        for ($i = 0; $i < $this->find_captcha_try_num; $i++) {
            try {
                $captcha = $this->driver->findElement(
                    WebDriverBy::cssSelector('div.idms-captcha-wrapper img')
                );
                return $captcha->getAttribute('src');

            } catch (\Exception $e) {
                sleep($this->find_captcha_wait_time);
                continue;
            }
        }
        return false;
    }


    protected function syncStatus($status)
    {
        $timestamp = time();
        $token = $this->getToken($timestamp);
        $api = $this->email_sync_status_api . '?robot_id=' . $this->robot_id . '&token=' . $token . '&timestamp=' . $timestamp . '&email=' . $this->email['email'] . '&status=' . $status;

        $ret = $this->httpGet($api);

        if ($ret['errno'] != 0) {
            $this->logSave(['tips' => 'sync status error:' . $ret['error']]);
            return false;
        }

        $data = json_decode($ret['data'], true);
        $log_arr = ['email' => $this->email['email'], 'resp_no' => $data['errno'], 'resp_error' => $data['error']];
        $this->logSave($log_arr);

        return true;
    }

    protected function inputPass()
    {
        //email
        $input = $this->driver->findElement(
            WebDriverBy::id('accountpassword')
        );
        $input->click();
        $input->sendKeys($this->appid_pass);

        return true;
    }



    protected function inputPasswd()
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('password')
        );
        $input->click();
        $input->sendKeys($this->user['password']);
        sleep(1);
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.password-input input')
        );
        $input->sendKeys($this->user['password']);

        return true;
    }

    protected function inputName()
    {
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('last-name-input input')
        );
        $input->sendKeys($this->user['last_name']);
        sleep(1);
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('first-name-input input')
        );
        $input->sendKeys($this->user['first_name']);

        return true;
    }

    protected function inputBirthday()
    {
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.birthday input')
        );
        $input->sendKeys($this->user['birthday']);
        return true;
    }

    protected function inputQuestion()
    {
        //question1
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set0 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set0 input')
        );
        $input->sendKeys($this->user['qst1_answer']);
        sleep(1);

        //question2
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set1 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set1 input')
        );
        $input->sendKeys($this->user['qst2_answer']);
        sleep(1);

        //question3
        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set2 select')
        );
        $select = new WebDriverSelect($input);
        $select->selectByIndex(2);

        $input = $this->driver->findElement(
            WebDriverBy::cssSelector('div.qa-set2 input')
        );
        $input->sendKeys($this->user['qst3_answer']);
        return true;
    }

    protected function getCaptchaCode()
    {
        for ($i = 0; $i < $this->captcha_try_num; $i++) {
            //$data = ['errno' => 0, 'data' => 'xixiha'];

            $api = $this->captcha_api . '/captcha/getcode?id=' . $this->captcha_id . '&robot_id=' . $this->robot_id;
            $ret = $this->httpGet($api);

            if ($ret['errno'] != 0) {
                $this->logSave(['tips' => 'getcode net error:' . $ret['error']]);
                $this->quit();
            }

            $data = json_decode($ret['data'], true);

            $log_arr = ['captcha_id' => $this->captcha_id, 'try_num' => $i, 'resp_no' => $data['errno'], 'resp_code' => $data['data'], 'tips' => 'Try Get Captcha Code'];

            if ($data['errno'] != 0) {
                $this->logSave($log_arr);
                sleep($this->captcha_wait_time);
                continue;
            }

            $log_arr['tips'] = 'get captcha code';
            $this->logSave($log_arr);

            return $data['data'];
        }
    }

    protected function inputCaptcha($code = '')
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('captchaInput')
        );
        $input->sendKeys($code);
        return true;
    }

    protected function createSubmit()
    {
        $link = $this->driver->findElement(
            WebDriverBy::cssSelector('div.flow-controls button')
        );
        $link->click();
        return true;
    }

    protected function checkStatus()
    {
        try {
            $this->driver->wait($this->create_page_submit_wait, 500)->until(
                WebDriverExpectedCondition::visibilityOfElementLocated(
                    WebDriverBy::cssSelector('div.success-icon-wrap')
                )
            );
            return true;
        } catch (\Exception $e) {
            $this->logSave(['tips' => 'Check Page Failed']);
            return false;
        }
    }

    protected function getVerifyCode()
    {
        for ($i = 0; $i < $this->email_try_num; $i++) {

            $email = $this->user['email'];
            $api = $this->email_api . '/email/getemailcode?email=' . $email;
            $ret = $this->httpGet($api, 10);

            if ($ret['errno'] != 0) {
                sleep($this->email_wait_time);
                continue;
            }

            $data = json_decode($ret['data'], true);

            $log_arr = ['email' => $email, 'try_num' => $i, 'code' => '', 'tips' => 'Try Get Email Code'];

            if ($data['data']['status'] != 0) {
                $this->logSave($log_arr);
                sleep($this->email_wait_time);
                continue;
            }

            $code = $data['data']['reason'];
            $log_arr['code'] = $code;
            $this->logSave($log_arr);

            return $code;
        }
        return false;
    }

    protected function verifySubmit()
    {
        $input_btn = $this->driver->findElements(
            WebDriverBy::cssSelector('div.flow-footer div.pull-right button')
        );
        $input_btn[2]->click();
        return true;
    }

    protected function checkVerify()
    {
        try {
            $this->driver->wait($this->create_page_submit_wait, 500)->until(
                WebDriverExpectedCondition::titleContains('Apple ID')
            );
            return true;
        } catch (\Exception $e) {
            $this->logSave(['tips' => 'Check Verify Failed']);
            return false;
        }
    }

    protected function resendSubmit()
    {
        $input_btn = $this->driver->findElement(
            WebDriverBy::cssSelector('div.resend-not-mobile-wrapper button')
        );
        $input_btn->click();
        return true;
    }

    protected function syncAccount()
    {
        $robot_id = $this->robot_id;
        $email = $this->user['email'];
        $password = $this->user['password'];
        $api = $this->email_api . "/email/updateemail?robot_id=$robot_id&email=$email&password=$password";
        $ret = $this->httpGet($api);

        $log_arr = ['email' => $email, 'resp' => $ret['data'], 'tips' => 'Register Success'];
        $this->logSave($log_arr);

        $user_log = $this->user;
        $user_log['tips'] = 'Register User Log';
        $this->logSave($user_log);
    }

    protected function inputVerifyCode($ver_code)
    {
        $input = $this->driver->findElement(
            WebDriverBy::id('char0')
        );
        $input->sendKeys($ver_code[0]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char1')
        );
        $input->sendKeys($ver_code[1]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char2')
        );
        $input->sendKeys($ver_code[2]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char3')
        );
        $input->sendKeys($ver_code[3]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char4')
        );
        $input->sendKeys($ver_code[4]);

        $input = $this->driver->findElement(
            WebDriverBy::id('char5')
        );
        $input->sendKeys($ver_code[5]);

        return true;
    }

    protected function quit()
    {
        $this->driver->quit();
        exit;
    }

    protected function httpPost($url, $data, $timeout = 5)
    {
        $ret = [
            'errno' => 0,
            'error' => '',
            'data' => '',
            'http_code' => 0,
        ];

        $post_data = $data;

        $ch = curl_init();

        curl_setopt ( $ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt ( $ch, CURLOPT_VERBOSE, $this->curl_verbose);
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_POST, 1 );
        curl_setopt ( $ch, CURLOPT_HEADER, 0 );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_USERAGENT, "Mozilla/5.0 QianZhuangApi/2.0");
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_data );

        $data = curl_exec($ch);

        $httpStatus = curl_getinfo($ch);
        $ret['http_code'] = $httpStatus['http_code'];

        if (empty($data)) {
            $ret['errno'] = 1;
            $ret['error'] = curl_error($ch);
        } else {
            $ret['data'] = $data;
        }
        curl_close($ch);

        return $ret;
    }

    protected function httpGet($url, $timeout = 5)
    {
        $ret = [
            'errno' => 0,
            'error' => '',
            'data' => '',
            'http_code' => 0,
        ];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 QianZhuangApi/2.0");
        curl_setopt($ch, CURLOPT_URL, $url);

        $data = curl_exec($ch);

        $httpStatus = curl_getinfo($ch);
        $ret['http_code'] = $httpStatus['http_code'];

        if ($this->debug >= 1) {
            $this->logSave(['tips' => 'HttpDebug', 'Request' => $url, 'Response' => $data]);
        }

        if (empty($data)) {
            $ret['errno'] = 1;
            $ret['error'] = curl_error($ch);
        } else {
            $ret['data'] = $data;
        }
        curl_close($ch);

        return $ret;
    }

    /**
     * 保存Log
     * @param array $log_arr
     */
    protected function logSave($log_arr = [])
    {
        $data = array_merge($this->log_arr, $log_arr);

        @$str = "[" . date('Y-m-d H:i:s') . "] ";
        foreach ($data as $k => $v) {
            $str .= "$k:$v, ";
        }
        $str .= PHP_EOL;
        file_put_contents('./run_log.txt', $str, FILE_APPEND);
    }


    /*
     * 用户获取邮件里面的url
     */
    public function getmaillink($email, $password)
    {
        $ret = array(
            'errno' => 0,
            'error' => '',
            'data' => array(
                'status' => 0,
                'reason' => '',
            ),
        );

        if(!($sock = fsockopen(gethostbyname(self::HOST), self::PORT, $errno, $errstr,5)))
        {
            $ret['data']['status'] = 1;
            $ret['data']['reason'] = 'pop3连接失败' . $errno . ", " . $errstr;
            return $ret;
        }

        stream_set_blocking($sock, true);

        $command = "USER " . $email . "\r\n";//用户名写入sock
        @fwrite($sock, $command);
        $msg = fgets($sock);
        $command = "PASS " . $password . "\r\n";//密码写入sock
        @fwrite($sock, $command);
        $msg = fgets($sock);
        $command = "stat\r\n";
        @fwrite($sock, $command);
        $msg = fgets($sock);

        if (preg_match('/-ERR Invalid login user or password/', $msg)) {
            $ret['data']['status'] = self::POP3_FAILED;
            $ret['data']['reason'] = '邮箱用户名与密码不匹配';
            return $ret;
        }
        $mail_content = '';
        @fwrite($sock, "RETR 1\r\n");

        try
        {
            pcntl_alarm(self::MAIL_TIMAE_OUT);//设置获取邮件正文的时间是10秒,超过10秒获取不到就结束

            $i = 0;
            while (true) {
                $i++;
                $msg = fgets($sock);
                $mail_content .= $msg;
                if (preg_match("/x-ds-vetting-token:(.*?)
X-Business-Group/i", $msg) || $i > 38
                ) {
                    break;
                }
            }
            pcntl_alarm(0);
        }
        catch(\Exception $e)
        {
            $ret['data']['status'] = self::POP3_FAILED;
            $ret['data']['reason'] = '获取邮件正文超时' . $e->getMessage();
            return $ret;
        }

        $command = "QUIT\r\n";
        @fwrite($sock, $command);//退出登录

        if (!preg_match("/apple.com>/i", $mail_content)) {
            $ret['data']['status'] = self::POP3_FAILED;
            $ret['data']['reason'] = '该邮箱最新一封邮件不是苹果公司发的邮件或者由于网络原因没有获取到邮件内容';
            return $ret;
        }

        preg_match("/;(.*?)\(CST/i", $mail_content, $time_match);
//        $mail_time = strtotime($time_match[1]);
//            if ($mail_time < time()) {
//                $ret['data']['status'] = self::POP3_FAILED;
//                $ret['data']['reason'] = '这不是最新的一封邮件';
//                return $ret;
//            }

        preg_match("/x-ds-vetting-token:(.*?)
X-Business-Group/i", $mail_content, $match);
        if (!empty($match[1])) {
            $ret['data']['status'] = self::POP3_SUCCESS;
            $link = 'https://id.apple.com/IDMSEmailVetting/vetemail.html?language=CN-ZH&key='. trim($match[1]) . '&type=DFT&_C=CHN&_L=zh_CN';
            $ret['data']['reason'] = $link;
            return $ret;
        }

        $ret['data']['status'] = self::POP3_FAILED;
        $ret['data']['reason'] = '系统未正确获取链接';
        return $ret;
    }


}

$auto = new Auto();


while (true) {
    $auto->start();
    sleep(5);
}



